#include "assert.h"
#include "mmu.h"
#include "lock.h"

#include "fs/deffs.h"
#include "fs/fs.h"
#include "fs/file.h"
#include "fs/inode.h"
#include "fs/vfs.h"
#include "fs/fat32.h"
#include "fs/device.h"

void
fs_init(void) {
    vfs_init();
    dev_init();
    fat32_init();
}

void
fs_cleanup(void) {
    vfs_cleanup();
}

void
files_lock(filesStruct_t* fp) {
    semaphore_acquire(&(fp->files_sem));
}

void
files_unlock(filesStruct_t* fp) {
    semaphore_release(&(fp->files_sem));
}

filesStruct_t*
files_create(void) {
    /**
     * @brief file buffer 由一个filesStruct开始，跟着buffer_size/file_size个file
     */
    filesStruct_t* fp = kmalloc(sizeof(filesStruct_t) + FILES_STRUCT_BUFFER_SIZE);
    if (fp != NULL) {
        fp->pwd = NULL;
        fp->fd_array = (void*)(fp + 1);  // TODO+1为跳过开头的fileStruct部分 测试是否可将void改为file_t
        fp->files_count = 0;
        semaphore_init(&(fp->files_sem), 1);
        fd_array_init(fp->fd_array);
    }
    return fp;
}

void
files_destroy(filesStruct_t* fp) {
    assert(fp != NULL && files_count(fp) == 0);  // TODO files_count==0?
    if (fp->pwd != NULL)
        vop_refDec(fp->pwd);
    file_t* fileList = fp->fd_array;
    for (int i = 0; i < FILES_STRUCT_NENTRY; ++i) {
        if (fileList[i].status == FD_OPENED)
            fd_array_close(&fileList[i]);
        assert(fileList[i].status == FD_NONE);
    }
    kmfree(fp);
}

void
files_closeAll(filesStruct_t* fp) {
    assert(fp != NULL && files_count(fp) > 0);
    file_t* fileList = fp->fd_array;
    for (int i = 2; i < FILES_STRUCT_NENTRY; ++i)
        if (fileList[i].status == FD_OPENED)
            fd_array_close(&fileList[i]);
}

int
files_dup(filesStruct_t*to,filesStruct_t*from){
    assert(to!=NULL&&from!=NULL);
    assert(files_count(to)==0&&files_count(from)>0);
    to->pwd = from->pwd;
    if(from->pwd!=NULL)vop_refInc(from->pwd);

    file_t *toFileList = to->fd_array, *fromFileList = from->fd_array;
    for (int i = 0; i < FILES_STRUCT_NENTRY;++i){
        if(fromFileList[i].status==FD_OPENED){
            toFileList[i].status = FD_INIT;
            fd_array_dup(&toFileList[i], &fromFileList[i]);
        }
    }
}